﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using WcfServer.Classes.Client;
using WcfServer.Classes.Server;
using WcfServer.Classes.Utility;
using System.ServiceModel.Channels;
using System.Security.Cryptography;

namespace WcfServer
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in both code and config file together.
    public class ServerService : IServerService
    {
        string ContainerName = "Server";
        static List<LoginData> ActiveLogins = new List<LoginData>();

        public ServerService(String ServerContainerName)
        {
            this.ContainerName = ServerContainerName;
        }

        public ServerService() { }


        public byte[] AuthenticateUser(byte[] loginInformation)
        {
            var en = new SharkEntities();
            var l = new LoginData(loginInformation, ContainerName);
            var res = (from items in en.Users where items.UserID == l.UserID && items.Password == l.Password select items);
            if (res.Any())
            {
                ActiveLogins.Add(l);
                var friendIds = (from items in en.User_User
                                 where (items.UserId == res.FirstOrDefault().ID) && items.Confirmed == true
                                 select items.FriendID).Union((from items in en.User_User
                                                      where (items.FriendID == res.FirstOrDefault().ID) && items.Confirmed == true
                                                      select items.UserId)).ToList();
                var friends = from items in en.Users where friendIds.Contains(items.ID) select items;
                List<UserSimple> friendsList= new List<UserSimple>();//TO ARMAN: update here for two way friendship
                
                foreach (var i in friends)
                {
                    var friendLoginInfo = ActiveLogins.Find(x => x.UserID == i.UserID);
                    friendsList.Add(new UserSimple()
                    {
                        FirstName = i.FirstName,
                        LastName = i.LastName,
                        UserID = i.UserID,
                        Port = friendLoginInfo == null? 0 : friendLoginInfo.listeningPort,
                        IP = friendLoginInfo == null ? "0.0.0.0" : friendLoginInfo.UserIP,
                        publicKey = i.PublicKey
                    });
                }

                return new LoginResponse()
                {
                    Friends = friendsList,
                    Sign = EncryptionHandler.EncryptRSA(EncryptionHandler.HashSHA256(SerializerHandler<List<UserSimple>>.SerializeInput(friendsList)),ContainerName)
                }.Send(l.UserSessionKey);
            }
            else
                return null;
        }

        public byte[] GetConnectionInformation(byte[] connectionRequest)
        {
            ConnectionRequest cr = new ConnectionRequest(connectionRequest);
            var SourceInfo = (from items in ActiveLogins where items.UserID == cr.srcName select items).FirstOrDefault();
            if(SourceInfo==null)
                return null;

            string targetuser = SerializerHandler<string>.DeSerializeInput(EncryptionHandler.DecryptAES(cr.EncryptedDstName, SourceInfo.UserSessionKey));

            var target = (from items in ActiveLogins where items.UserID == targetuser select items).FirstOrDefault();
            if(target==null)
                return null;

            var TempSessionKey = KeyHandler.generateAESKey();
            var T_ = DateTime.Now;

            var clientoken = new UserResponse()
            {
                ReceiverID = target.UserID,
                ReceiverIP = target.UserIP,
                SenderID = SourceInfo.UserID,
                SenderIP = SourceInfo.UserIP,
                SessionKey = TempSessionKey,
                TimeStamp = T_
            };
            var targettoken = new UserResponse()
            {
                ReceiverID = target.UserID,
                ReceiverIP = target.UserIP,
                SenderID = SourceInfo.UserID,
                SenderIP = SourceInfo.UserIP,
                SessionKey = TempSessionKey,
                TimeStamp = T_
            };
            var m = new MainResponse()
            {
                ClientToken = EncryptionHandler.EncryptAES(SerializerHandler<UserResponse>.SerializeInput(clientoken),SourceInfo.UserSessionKey),
                TargetToken = EncryptionHandler.EncryptAES(SerializerHandler<UserResponse>.SerializeInput(targettoken), target.UserSessionKey),
            };
            return SerializerHandler<MainResponse>.SerializeInput(m);
        }

        public String SignUp(byte[] SignUpInfo)
        {
            var db = new SharkEntities();
            var temp = new SignUpRequest(SignUpInfo);
            //TODO: CHECK FOR VALIDITY OF HASHED PUBLIC KEY VS PUBLIC KEY
            SignUpUserInfo userInfo = new SignUpUserInfo(EncryptionHandler.DecryptRSA(temp.userInfo,"Server"));//IS it using private key to decrypt?
            User u = new User();
            u.Avatar = userInfo.Avatar;
            u.UserID = userInfo.UserID;
            u.FirstName = userInfo.FirstName;
            u.LastName = userInfo.LastName;
            u.Password = userInfo.Password;

            db.Users.Add(u);

            if( db.SaveChanges() == 1)
            {
                return "Successfully Created.";
            }
            return null;         
        }
    }
}
